﻿
/**
 * drm_plane_init
 * kirin_drm_ops->kirin_drm_bind->kirin_drm_kms_init->kirin_drm_private_init->drm_vblank_init
 */

static int kirin_drm_kms_init(struct drm_device *dev,
			      const struct kirin_drm_data *driver_data)
{
	int ret;

	/* dev->mode_config initialization */
	drm_mode_config_init(dev);

	dev->mode_config.min_width = 0;
	dev->mode_config.min_height = 0;
	dev->mode_config.max_width = driver_data->config_max_width;
	dev->mode_config.max_height = driver_data->config_max_width;
	dev->mode_config.funcs = driver_data->mode_config_funcs;

	/* display controller init */
	ret = kirin_drm_private_init(dev, driver_data);


	/* bind and init sub drivers */
	/* 本例中只会调用dsi的bind函数 dsi_bind  */
	ret = component_bind_all(dev->dev, dev);


	/* vblank init */
	/* crtc初始化之后  dev->mode_config.num_crtc会变化 */
	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);

	/* with irq_enabled = true, we can use the vblank feature. */
	dev->irq_enabled = true;

	/* reset all the states of crtc/plane/encoder/connector */
	drm_mode_config_reset(dev);

	/* init kms poll for handling hpd */
	drm_kms_helper_poll_init(dev);

	return 0;
}

/**
 * drm_vblank_init - initialize vblank support
 * @dev: DRM device
 * @num_crtcs: number of CRTCs supported by @dev
 *
 * This function initializes vblank support for @num_crtcs display pipelines.
 * Cleanup is handled automatically through a cleanup function added with
 * drmm_add_action_or_reset().
 *
 * Returns:
 * Zero on success or a negative error code on failure.
 */
int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
{
	int ret;
	unsigned int i;

	spin_lock_init(&dev->vbl_lock);
	spin_lock_init(&dev->vblank_time_lock);

	dev->vblank = drmm_kcalloc(dev, num_crtcs, sizeof(*dev->vblank), GFP_KERNEL);

	dev->num_crtcs = num_crtcs;

	for (i = 0; i < num_crtcs; i++) {
		/* vblank和crtc是一一对应的 */
		struct drm_vblank_crtc *vblank = &dev->vblank[i];

		vblank->dev = dev;
		vblank->pipe = i;
		init_waitqueue_head(&vblank->queue);
		timer_setup(&vblank->disable_timer, vblank_disable_fn, 0);
		seqlock_init(&vblank->seqlock);

		ret = drmm_add_action_or_reset(dev, drm_vblank_init_release,
					       vblank);

		ret = drm_vblank_worker_init(vblank);

	}
}

int drm_vblank_worker_init(struct drm_vblank_crtc *vblank)
{
	struct kthread_worker *worker;

	INIT_LIST_HEAD(&vblank->pending_work);

	init_waitqueue_head(&vblank->work_wait_queue);

	worker = kthread_create_worker(0, "card%d-crtc%d",
				       vblank->dev->primary->index,
				       vblank->pipe);

	vblank->worker = worker;

	sched_set_fifo(worker->task);
	return 0;
}

